Package edu.gatech.math2605.kzhou33.client

Source Code of edu.gatech.math2605.kzhou33.client.Pinball$startHandler

package edu.gatech.math2605.kzhou33.client;

import java.util.ArrayList;

import org.vaadin.gwtgraphics.client.DrawingArea;
import org.vaadin.gwtgraphics.client.shape.Path;
import org.vaadin.gwtgraphics.client.shape.Rectangle;
import org.vaadin.gwtgraphics.client.shape.Text;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.ToggleButton;
import com.google.gwt.user.client.ui.VerticalPanel;

public class Pinball implements EntryPoint {

  private double angleLimit = 360;
  private int WIDTH = 500, HEIGHT = 500, circleRadius = 60, ballRadius = 2,
      side = 360; // radius < side/2
  private ArrayList<Integer> lastCircle = new ArrayList<Integer>();
  private DrawingArea gwtCanvas;
  private VirtualCircle c1, c2, c3, ball;
  private FastCircle ballFast;

  private TextBox angleBox, sideBox, circleRadiusBox, ballRadiusBox;
  private FlexTable infoLabel, testLabel;
  private Path[] path;
  private DockLayoutPanel dlp;
  private boolean isSlow = true;
  private double[] max = new double[2];
  private double initAngle, angle;
  private int hits = 0, pathNum = 0;

  private int[] freq = new int[1000];
  private TextBox numTrials;
  private CheckBox randomOrEqual;
  private ArrayList<Result> results = new ArrayList<Result>();
  private Result tempResult;

  // 85.88801
  public void onModuleLoad() {
    lastCircle.add(0);
    max[0] = max[1] = 0;
    dlp = new DockLayoutPanel(Unit.PCT);
    VerticalPanel vp = createSidePanel();
    HorizontalPanel ap = createCanvas(WIDTH, HEIGHT, circleRadius,
        ballRadius, side);

    dlp.addWest(new ScrollPanel(vp), 20);

    dlp.add(new ScrollPanel(ap));

    RootLayoutPanel.get().add(dlp);
  }

  private VerticalPanel createSidePanel() {
    VerticalPanel vp = new VerticalPanel();

    Button start = new Button("Start");
    start.addClickHandler(new startHandler("start"));

    Button reset = new Button("Reset/ Update");
    reset.addClickHandler(new startHandler("reset"));
    Button clear = new Button("Clear Trail");
    clear.addClickHandler(new startHandler("clear"));
    Button special = new Button("Run Many");
    special.addClickHandler(new startHandler("special"));

    sideBox = new TextBox();
    circleRadiusBox = new TextBox();
    ballRadiusBox = new TextBox();
    angleBox = new TextBox();

    sideBox.setText(side + "");
    circleRadiusBox.setText(circleRadius + "");
    ballRadiusBox.setText(ballRadius + "");
    angleBox.setText(String.valueOf(angle));

    final TextBox incre = new TextBox();
    incre.setText("2");
    randomOrEqual = new CheckBox(
        "random if checked/ otherwise equally spaced");

    angleBox.addKeyDownHandler(new KeyDownHandler() {

      public void onKeyDown(KeyDownEvent event) {
        if (event.isUpArrow()) {
          angle += Double.valueOf(incre.getText());
          angleBox.setText(angle + "");
          if (validate()) {
            run(angle);
          }
        } else if (event.isDownArrow()) {
          angle -= Double.valueOf(incre.getText());
          angleBox.setText(angle + "");
          if (validate()) {
            run(angle);
          }
        } else if (event.isRightArrow()) {
          incre.setText((Double.valueOf(incre.getText()) * (1 / 2d))
              + "");
          //angleBox.setText(angleBox.getText().replace(oldChar, newChar)

        } else if (event.isLeftArrow()) {
          incre.setText((Double.valueOf(incre.getText()) * 2d) + "");

        } else if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {

          if (validate()) {
            reset();
            run(angle);
          }
        }

      }
    });

    vp.add(new Label("Pinball Project"));
    vp.add(new Label("Created by"));
    vp.add(new Label("Kefu Zhou"));
    vp.add(new Label("Angle in degrees (0-360)"));
    vp.add(angleBox);
    vp.add(new Label("Triangle side length"));
    vp.add(sideBox);
    vp.add(new Label("Circle radius"));
    vp.add(circleRadiusBox);
    vp.add(new Label("Ball radius (still a point)"));
    vp.add(ballRadiusBox);
    vp.add(new Label("Increment"));
    vp.add(incre);
    HorizontalPanel hp = new HorizontalPanel();
    hp.add(start);
    hp.add(reset);
    hp.add(clear);
    vp.add(hp);

    HorizontalPanel hp2 = new HorizontalPanel();
    hp2.add(special);
    numTrials = new TextBox();
    hp2.add(numTrials);
    vp.add(hp2);
    vp.add(randomOrEqual);

    final ToggleButton showFreq = new ToggleButton("Show Freq Table",
        "Hide Freq Table");
    showFreq.addClickHandler(new ClickHandler() {

      private FreqPopup fp;

      public void onClick(ClickEvent event) {
        if (showFreq.isDown()) {
          if (fp == null) {
            fp = new FreqPopup(freq);
            // fp.setAutoHideEnabled(true);
          } else {
            fp.update(freq);
          }
          // fp.setHeight("100%");
          fp.show();
          fp.center();
        } else {
          fp.hide();
        }
      }
    });

    vp.add(showFreq);

    Button topTen = new Button("Show top 10");
    vp.add(topTen);
    topTen.addClickHandler(new ClickHandler() {

      public void onClick(ClickEvent event) {
        Grid g = null;
        PopupPanel pop = null;
        if (g == null) {
          pop = new PopupPanel();
          pop.setAutoHideEnabled(true);
          g = new Grid(11, 3);
          g.setText(0, 0, "Top");
          g.setText(0, 1, "Initial Angle");
          g.setText(0, 2, "Circles hit");
          pop.add(g);
        }
        for (int i = 0; i < results.size(); i++) {
          g.setText(i + 1, 0, i + 1 + "");
          g.setText(i + 1, 1, results.get(i).getInitialAngle() + "");
          g.setText(i + 1, 2, results.get(i).printHitSequence());
        }
        pop.show();
        pop.center();

      }
    });

    final CheckBox angleLimitBox = new CheckBox("0-120 instead of 0-360");
    angleLimitBox.addClickHandler(new ClickHandler() {

      public void onClick(ClickEvent event) {
        if (angleLimitBox.getValue()) {
          angleLimit = 120d;
        } else
          angleLimit = 360d;
      }
    });
    vp.add(angleLimitBox);

    testLabel = new FlexTable();
    testLabel.setStyleName("infoLabel");
    testLabel.getColumnFormatter().setStyleName(0, "even");
    testLabel.getColumnFormatter().setStyleName(1, "odd");
    testLabel.getColumnFormatter().setStyleName(2, "even");
    testLabel.getColumnFormatter().setStyleName(3, "odd");
    testLabel.getColumnFormatter().setStyleName(4, "even");

    return vp;
  }

  private HorizontalPanel createCanvas(int WIDTH, int HEIGHT,
      int circleRadius, int ballRadius, int side) { // radius < side/2) {
    HorizontalPanel panel = new HorizontalPanel();

    double yCTR = HEIGHT / 2;
    double xCTR = WIDTH / 2;
    double c1_x = xCTR;
    double c1_y = yCTR;
    double c2_x = xCTR;
    double c2_y = yCTR;
    double c3_x = xCTR;
    double c3_y = yCTR;

    c1_x += 0;
    c1_y += side * Math.sqrt(3) / 3.0;
    c2_x -= side / 2.0f;
    c2_y -= side * Math.sqrt(3) / 6.0;
    c3_x += side / 2.0f;
    c3_y -= side * Math.sqrt(3) / 6.0;

    c1 = new VirtualCircle(c1_x, c1_y, circleRadius);
    c2 = new VirtualCircle(c2_x, c2_y, circleRadius);
    c3 = new VirtualCircle(c3_x, c3_y, circleRadius);

    String property = "orange";
    c1.setFillColor(property);
    c2.setFillColor(property);
    c3.setFillColor(property);

    // ballRadius = 15;
    ball = new VirtualCircle(xCTR, yCTR, ballRadius);
    ball.setFillColor("red");

    ballFast = new FastCircle(xCTR, yCTR, ballRadius);

    gwtCanvas = new DrawingArea(WIDTH, HEIGHT);

    gwtCanvas.add(new Rectangle(0, 0, WIDTH, HEIGHT));

    gwtCanvas.add(c1);
    gwtCanvas.add(c2);
    gwtCanvas.add(c3);
    gwtCanvas.add(ball);
    if (isSlow) {
      path = new Path[1];
      for (int i = 0; i < path.length; i++) {
        path[i] = new Path(WIDTH / 2, HEIGHT / 2);
        path[i].setStrokeWidth(1);
        path[i].setStrokeColor("blue");
        path[i].setFillOpacity(0.00);
        gwtCanvas.add(path[i]);
      }
      path[0].setStrokeColor("black");
      // path[1].setStrokeColor("blue");
      // path[2].setStrokeColor("blue");
      // path[3].setStrokeColor("blue");
      // path[4].setStrokeColor("indigo");
    }
    Text t1 = new Text(c2.getX() - 50, c2.getY(), "Created by");
    Text t2 = new Text(c3.getX() - 50, c3.getY(), "Kefu Zhou");
    Text c3Text = new Text(c3.getX(), c2.getY() + 20, "3");
    Text c2Text = new Text(c2.getX(), c3.getY() + 20, "2");
    Text c1Text = new Text(c1.getX(), c1.getY() + 20, "1");
    gwtCanvas.add(t1);
    gwtCanvas.add(t2);

    gwtCanvas.add(c1Text);
    gwtCanvas.add(c2Text);
    gwtCanvas.add(c3Text);

    panel.add(gwtCanvas);

    infoLabel = new FlexTable();
    infoLabel.setStyleName("infoLabel");
    infoLabel.getColumnFormatter().setStyleName(0, "even");
    infoLabel.getColumnFormatter().setStyleName(1, "odd");
    infoLabel.getColumnFormatter().setStyleName(2, "even");
    infoLabel.getColumnFormatter().setStyleName(3, "odd");
    infoLabel.getColumnFormatter().setStyleName(4, "even");

    createTableHeaders();

    VerticalPanel vp = new VerticalPanel();
    vp.add(testLabel);
    vp.add(infoLabel);
    vp.add(new HTML(
        "<div><span style=\"text-align: -webkit-left; \"><font color=\"#ff0000\" size=\"2\"><div>Instructions:</div>"
            + "<div>1) Click on angle textbox</div>"
            + "<div>2) Press the up/down arrow key to +/- angle by value specified in increment box</div>"
            + "<div>3) Change increment by changing value in increment box, or press left/right arrow key while on angle box to multiply or divide by 0.1</div>"
            + "<div><br></div>"
            + "<div>Legend:</div>"
            + "<div>Angle Box (degrees): initial angle clockwise from East</div>"
            + "<div>Side Length Box (pixels) : distance from origin of one circle to another circle</div>"
            + "<div>Circle Radius (pixels): Radius of circle</div>"
            + "<div>Ball Radius (pixels): Radius of pinball (does not affect result)</div>"
            + "<div>Increment (degrees): Value to change by when (up,right)/(down/left) is pressed</div>"
            + "<div><br></div>"
            + "<div>Start: Run once with path enabled</div>"
            + "<div>Reset/ Update: redraw canvas area</div>"
            + "<div>Clear: Clears the path</div>"
            + "<div>Run many: Runs simulation for specified iterations</div>"
            + "<div>Checkbox #1: check for random angles, otherwise equally spaced angles</div>"
            + "<div>Show Freq Table: Shows number of results at each hit</div>"
            + "<div>Show Top 10: Shows top twn initial angles and circles hit</div>"
            + "<div>Checkbox #2: check to use range 0-120 instead of 0-360</div>"
            + "</font></span></div>"));

    ScrollPanel sp = new ScrollPanel();
    sp.add(vp);
    sp.setHeight(gwtCanvas.getHeight() + "px");
    panel.add(sp);
    return panel;

  }

  public boolean moveObject(VirtualCircle b) {
    boolean cancel = false;
    // move
    b.moveV();

    // check collision
    if (lastCircle.get(lastCircle.size() - 1) != 1
        && PinballMath.intersect(c1, ball) != -1) {
      doPhysics(c1, ball, 1);
    } else if (lastCircle.get(lastCircle.size() - 1) != 2
        && PinballMath.intersect(c2, ball) != -1) {
      doPhysics(c2, ball, 2);
    } else if (lastCircle.get(lastCircle.size() - 1) != 3
        && PinballMath.intersect(c3, ball) != -1) {
      doPhysics(c3, ball, 3);
    } else {
      // hits++;// make it start at 1
      freq[hits]++;
      logMax();
      hits = 0;
      if (isSlow) {
        path[pathNum].lineTo(
            (int) (ball.getVx() + WIDTH * ball.getDx()),
            (int) (ball.getVy() + WIDTH * ball.getDy()));
      }
      ball.setVxy(WIDTH / 2, HEIGHT / 2);
      ball.setDxy(0, 0);
      cancel = true;
    }
    return cancel;
  }

  private void doPhysics(VirtualCircle a, VirtualCircle b, int i) {
    hits++;
    lastCircle.add(i);
    double intersectTime = PinballMath.intersect(a, b);
    b.setVxy(b.getVx() + intersectTime * b.getDx(), b.getVy()
        + intersectTime * b.getDy());
    // TODO animate, use intersect time
    double[] tempReflect = PinballMath.reflect(a, b);
    b.setDxy(tempReflect[0], tempReflect[1]);
    if (isSlow) {
      path[pathNum].lineTo(b.getX(), b.getY());
      logToTable(intersectTime, b.getVx(), b.getVy());
    }
  }

  private void logToTable(double intersectTime, double vx, double vy) {
    if (isSlow) {
      int row = infoLabel.getRowCount();
      double old = (row == 1 ? 0 : Double.valueOf(infoLabel.getText(
          row - 1, 1)));

      infoLabel.setText(row, 0, hits + "");
      infoLabel.setText(row, 1, (intersectTime + old) + "");
      infoLabel.setText(row, 2, vx + "");
      infoLabel.setText(row, 3, vy + "");
      infoLabel.setText(row, 4, intersectTime + "");
    }
  }

  private void logMax() {
    if (hits >= max[0]) {
      lastCircle.remove(0);
      tempResult = new Result(initAngle, lastCircle);
      results.add(0, tempResult);
      while (results.size() > 10) {
        results.remove(10);
      }
      max[0] = hits;
      max[1] = initAngle;
    }
    testLabel.setText(1, 0, max[0] + "");
    testLabel.setText(1, 1, max[1] + "");
  }

  private class startHandler implements ClickHandler {
    String source = "";

    public startHandler(String source) {
      this.source = source;
    }

    public void onClick(ClickEvent event) {

      if (validate()) {
        if (source.equals("start")) {
          run(angle);
        } else if (source.equals("special")) {
          isSlow = false;
          int numRuns = Integer.valueOf(numTrials.getText());
          if (randomOrEqual.getValue()) {
            for (int i = 0; i < numRuns; i++) {
              runFast(Math.random() * angleLimit);
            }
          } else {
            double dEqual = angleLimit / numRuns;
            double current = 0;
            for (int i = 0; i < numRuns; i++) {
              runFast(current);
              current += dEqual;
            }
          }
          isSlow = true;
        } else if (source.equals("reset")) {
          reset();
          dlp.remove(1);
          dlp.add(new ScrollPanel(createCanvas(WIDTH, HEIGHT,
              circleRadius, ballRadius, side)));
        } else if (source.equals("clear")) {
          for (int i = 0; i < path.length; i++)
            removePath(i);
        } else if (source.equals("update")) {

        }

      }
    }

  }

  private void setAngle(IsCircle a, double theta) {
    a.setDxy(Math.cos(theta), (Math.sin(theta)));
  }

  private void reset() {
    pathNum = 0;
    for (int i = 0; i < path.length; i++)
      path[i].moveTo(WIDTH / 2, HEIGHT / 2);
    ball.setVxy(WIDTH / 2, HEIGHT / 2);
    ball.setDxy(0, 0);
    // freq[hits]++;
    hits = 0;
    infoLabel.removeAllRows();
    testLabel.removeAllRows();
    createTableHeaders();
  }

  private void run(double angle) {
    if (isSlow) {
      if (infoLabel.getRowCount() > 1) {
        infoLabel.removeAllRows();
        testLabel.removeAllRows();
        createTableHeaders();
      }
      if (pathNum + 1 == path.length) {
        pathNum = 0;
      } else {
        pathNum++;
      }
      removePath(pathNum);
    }
    lastCircle.clear();
    lastCircle.add(0);
    initAngle = angle;
    ball.setVxy(WIDTH / 2, HEIGHT / 2);

    setAngle(ball, angle * Math.PI / 180);
    while (moveObject(ball) != true) {
    }

  }

  private void removePath(int pathNum) {
    for (int i = 0; i < path.length; i++) {
      while (path[pathNum].getStepCount() != 0) {
        path[pathNum].removeStep(0);
      }
      path[pathNum].moveTo(WIDTH / 2, HEIGHT / 2);
    }
  }

  private void createTableHeaders() {
    infoLabel.setText(0, 0, "Hit # ");
    infoLabel.setText(0, 1, "Time (ms)");
    infoLabel.setText(0, 2, "X-coordinate (px)");
    infoLabel.setText(0, 3, "Y-coordinate (px)");
    infoLabel.setText(0, 4, "Time Gap (ms)");

    testLabel.setText(0, 0, "Maximum Count");
    testLabel.setText(0, 1, "Angle");
    testLabel.setText(1, 0, "null");
    testLabel.setText(1, 1, "null");
  }

  private boolean validate() {
    boolean result;
    try {
      circleRadius = Integer.valueOf(circleRadiusBox.getText());
      ballRadius = Integer.valueOf(ballRadiusBox.getText());
      side = Integer.valueOf(sideBox.getText());
      if (circleRadius >= side / 2) {
        Window.alert("Circle radius must be less than side/2");
      }
      angle = Double.parseDouble(angleBox.getText());
      if (angle >= 360) {
        angleBox.setText(angle % 360 + "");
        angle %= 360;
      }

      result = true;
    } catch (Exception e) {
      Window.alert("Please check inputs");
      result = false;
    }
    return result;
  }

  public void runFast(double angle) {
    hits = 0;
    lastCircle.clear();
    lastCircle.add(0);
    initAngle = angle;
    ballFast.setVxy(WIDTH / 2, HEIGHT / 2);

    setAngle(ballFast, angle * Math.PI / 180);
    while (moveObjectFast(ballFast) != true)
      ;
  }

  public boolean moveObjectFast(IsCircle b) {
    boolean cancel = false;
    // move
    b.moveV();
    // check collision
    if (lastCircle.get(lastCircle.size() - 1) != 1
        && PinballMath.intersect(c1, ballFast) != -1) {
      doPhysicsFast(c1, ballFast, 1);
    } else if (lastCircle.get(lastCircle.size() - 1) != 2
        && PinballMath.intersect(c2, ballFast) != -1) {
      doPhysicsFast(c2, ballFast, 2);
    } else if (lastCircle.get(lastCircle.size() - 1) != 3
        && PinballMath.intersect(c3, ballFast) != -1) {
      doPhysicsFast(c3, ballFast, 3);
    } else {
      freq[hits]++;
      logMax();
      cancel = true;
    }
    return cancel;
  }

  private void doPhysicsFast(IsCircle a, IsCircle b, int i) {
    hits++;
    lastCircle.add(i);
    double intersectTime = PinballMath.intersect(a, b);
    b.setVxy(b.getVx() + intersectTime * b.getDx(), b.getVy()
        + intersectTime * b.getDy());
    double[] tempReflect = PinballMath.reflect(a, b);
    b.setDxy(tempReflect[0], tempReflect[1]);
  }

}
TOP

Related Classes of edu.gatech.math2605.kzhou33.client.Pinball$startHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.